using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ManagedAPI;

namespace UnitTest.Derived
{
	/// <summary>
	/// Summary description for ClassTypeTest
	/// </summary>
	[TestClass]
	public class ClassTypeTest
	{
		public ClassTypeTest()
		{

		}

		#region Additional test attributes
		//
		// You can use the following additional attributes as you write your tests:
		//
		// Use ClassInitialize to run code before running the first test in the class
		// [ClassInitialize()]
		// public static void MyClassInitialize(TestContext testContext) { }
		//
		// Use ClassCleanup to run code after all tests in a class have run
		// [ClassCleanup()]
		// public static void MyClassCleanup() { }
		//
		// Use TestInitialize to run code before running each test 
		private static bool mOpenResult;
		[TestInitialize()]
		public void MyTestInitialize()
		{
			mOpenResult = Database.Open(UnderstandGlobalData.GetFileName());
			Assert.IsTrue(mOpenResult);
		}
		//
		// Use TestCleanup to run code after each test has run
		[TestCleanup()]
		public void MyTestCleanup()
		{
			Database.Close();
			mOpenResult = false;
		}
		//
		#endregion

		[TestMethod]
		public void TestClassType()
		{
			FileEntity fileEnt = Database.LookupFileEntity("classes.h");
			Assert.AreEqual("classes.h", fileEnt.NameShort);
			Assert.IsTrue(fileEnt != null);

			ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
			Assert.AreEqual(5, classtypes.Length);
			Assert.IsTrue(classtypes != null);

			ClassType mommy = classtypes[3];
			Assert.AreEqual("Mommy", mommy.NameLong);
			Entity[] functions = mommy.GetMethods();
			Assert.AreEqual("class Mommy", mommy.ToString());
			Assert.AreEqual("Mommy::Mommy", functions[0].NameLong);
			Assert.AreEqual("Mommy::fn_one", functions[1].NameLong);
			Assert.AreEqual("Mommy::fn_two", functions[2].NameLong);

			Assert.AreEqual("C Public Member Function", functions[0].KindName);
			Assert.AreEqual("C Public Member Function", functions[1].KindName);
			Assert.AreEqual("C Public Member Function Virtual", functions[2].KindName);
		}

		[TestMethod]
		public void TestClassTypeFields()
		{
			FileEntity fileEnt = Database.LookupFileEntity("classes.h");
			Assert.AreEqual("classes.h", fileEnt.NameShort);
			Assert.IsTrue(fileEnt != null);

			ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
			Assert.AreEqual(5, classtypes.Length);
			Assert.IsTrue(classtypes != null);

			ClassType mommy = classtypes[3];
			Assert.AreEqual("Mommy", mommy.NameLong);
			Entity[] fields = mommy.GetFields();

			Assert.AreEqual(9, fields.Length);
			Assert.AreEqual("my_priv_int", fields[0].NameShort);
			Assert.AreEqual("my_static_int", fields[1].NameShort);
			Assert.AreEqual("my_defined_static", fields[2].NameShort);

			Assert.AreEqual("my_prot_int", fields[3].NameShort);
			Assert.AreEqual("my_static_prot_int", fields[4].NameShort);
			Assert.AreEqual("my_pub_int", fields[5].NameShort);
			Assert.AreEqual("my_static_pub_int", fields[6].NameShort);

			Assert.AreEqual("C Private Member Object", fields[0].KindName);
			Assert.AreEqual("C Unresolved Private Member Object Static", fields[1].KindName);
			Assert.AreEqual("C Private Member Object Static", fields[2].KindName);

			Assert.AreEqual("C Protected Member Object", fields[3].KindName);
			Assert.AreEqual("C Unresolved Protected Member Object Static", fields[4].KindName);
			Assert.AreEqual("C Public Member Object", fields[5].KindName);
			Assert.AreEqual("C Unresolved Public Member Object Static", fields[6].KindName);

			// The union member
			Assert.AreEqual("goo", fields[7].NameShort);
			Assert.AreEqual("C Public Member Object", fields[7].KindName);
			Assert.AreEqual("FPValue", fields[7].TypeText);
			Assert.AreEqual("Mommy::goo", fields[7].NameLong);
		}

		[TestMethod]
		public void TestClassTypeInheritance()
		{
			FileEntity fileEnt = Database.LookupFileEntity("classes.h");
			ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
			ClassType older = classtypes[2];
			Assert.AreEqual("Older", older.NameShort);
			ClassType[] base_classes = older.GetBaseClasses();
			Assert.AreEqual(2, base_classes.Length);

			Assert.AreEqual("Derived", base_classes[0].NameLong);
			Assert.AreEqual("OtherBase", base_classes[1].NameLong);

			ClassType[] all_base_classes = older.GetAllBaseClasses();
			Assert.AreEqual(3, all_base_classes.Length);
			Assert.AreEqual("Derived", all_base_classes[0].NameShort);
			Assert.AreEqual("Base", all_base_classes[1].NameShort);
			Assert.AreEqual("OtherBase", all_base_classes[2].NameShort);
		}

		[TestMethod]
		public void TestClassTypeDerivedFrom()
		{
			FileEntity fileEnt = Database.LookupFileEntity("base.h");
			ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
			ClassType baseEnt = classtypes[0];
			Assert.AreEqual("Base", baseEnt.NameShort);
			ClassType[] derivedClasses = baseEnt.GetDerivedClasses();
			Assert.IsTrue(derivedClasses != null);
			Assert.AreEqual(3, derivedClasses.Length);

			ClassType[] allderivedClasses = baseEnt.GetAllDerivedClasses();
			Assert.IsTrue(allderivedClasses != null);
			Assert.AreEqual(4, allderivedClasses.Length);
			Assert.AreEqual("Derived", allderivedClasses[0].NameShort);
			Assert.AreEqual("Older", allderivedClasses[1].NameShort);
			Assert.AreEqual("Younger", allderivedClasses[2].NameShort);
			Assert.AreEqual("Mommy", allderivedClasses[3].NameShort);
		}

		[TestMethod]
		public void TestClassTypeEnums()
		{
			FileEntity fileEnt = Database.LookupFileEntity("classes.h");
			ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
			ClassType mommy = classtypes[3];
			Assert.AreEqual("Mommy", mommy.NameShort);
			EnumType[] enumEnts = mommy.GetEnums();
			Assert.AreEqual(1, enumEnts.Length);
			EnumType gofer = enumEnts[0];
			Assert.AreEqual("gofer", gofer.NameShort);
			Assert.AreEqual(null, gofer.TypeText);
			Assert.AreEqual("C Private Member Enum Type", gofer.KindName);
		}

		[TestMethod]
		public void TestClassTypeTemplates()
		{
			FileEntity fileEnt = Database.LookupFileEntity("foo_Util.h");
			ClassType[] classes = fileEnt.GetClassTypeDefinitions();
			ClassType stamper = classes[1];
			Assert.AreEqual("Stamper", stamper.NameShort);
		}

		[TestMethod]
		public void TestClassTypeUnions()
		{
			FileEntity fileEnt = Database.LookupFileEntity("classes.h");
			ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
			ClassType mommy = classtypes[3];
			Entity[] mommy_unions = mommy.GetUnions();
			Assert.IsTrue(mommy_unions != null);
			Assert.AreEqual(1, mommy_unions.Length);
			Entity goo = mommy_unions[0];
			Assert.IsTrue(goo != null);
			Assert.AreEqual("Mommy::FPValue", goo.NameLong);
			Assert.AreEqual(null, goo.TypeText);
			Assert.AreEqual("C Public Member Union Type", goo.KindName);

			Reference[] goo_refs = goo.Refs("Define", "Members");
			Assert.IsTrue(null != goo_refs);
			Assert.AreEqual(2, goo_refs.Length);
			Assert.AreEqual("i", goo_refs[0].ThisEntity.NameShort);
			Assert.AreEqual("f", goo_refs[1].ThisEntity.NameShort);
		}

		[TestMethod]
		public void TestClassNests()
		{
			FileEntity fileEnt = Database.LookupFileEntity("foo_util.h");
			ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
			
			ClassType outer = classtypes[2];
			Assert.IsFalse(outer.IsDefinedInsideClass);
			
			ClassType inner = classtypes[3];
			Assert.IsTrue(inner.IsDefinedInsideClass);
		}

		[TestMethod]
		public void TestGetMethods()
		{
			FileEntity fileEnt = Database.LookupFileEntity("classes.h");
			ClassType[] classes = fileEnt.GetClassTypeDefinitions();
			ClassType derived = classes[0];

			MethodType[] derivedMethods = derived.GetMethods();
			Assert.AreEqual(5, derivedMethods.Length);

			ClassType mommy = classes[3];
			MethodType[] mommyMethods = mommy.GetMethods();
			Assert.AreEqual(8, mommyMethods.Length);
		}

		[TestMethod]
		public void TestGetDefinedMethods()
		{
			FileEntity fileEnt = Database.LookupFileEntity("foo_Util.h");
			ClassType[] classes = fileEnt.GetClassTypeDefinitions();
			ClassType outer = classes[2];
			Assert.AreEqual("NestedOuter", outer.NameSimple);
			MethodType[] methods = outer.GetMethods();
			Assert.AreEqual(3, methods.Length);
			
			foreach (MethodType method in methods)
			{
				Reference[] methodRefs = method.Refs("Define", "Object Local");
				if (methodRefs.Length > 0)
				{
					foreach (Reference reff in methodRefs)
					{
						System.Diagnostics.Debug.Print("{0} -- {1} -- {2}", reff.Kind.NameLong, reff.ThisEntity.GetCleanType(), reff.ThisEntity.NameLong);
					}
				}
			}
		}
	}
}
